/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import EventEmitter from 'events';
import * as http from 'http';
import { Server, Socket } from 'socket.io';

export enum DaemonServerEventName {
  CONNECTION = 'connection',
  LISTENING = 'listening',
  LISTEN_FAILED = 'listenFailed',
  CLOSE_CONNECTION = 'closeConnection',
  CLOSE_SERVER = 'closeServer',
  ERROR = 'error',
}

/**
 * daemon process中运行的server
 */
export class HvigorDaemonServer extends EventEmitter {
  private static instance: HvigorDaemonServer;
  private server: Server;
  private readonly httpServer: http.Server;
  private readonly sessionId: string;

  constructor(sessionId: string) {
    super();
    this.httpServer = http.createServer();
    this.server = new Server(this.httpServer, {
      path: `/${sessionId}`,
      pingInterval: 60000,
      pingTimeout: 60000,
    });
    this.sessionId = sessionId;
  }

  static getInstance(sessionId: string): HvigorDaemonServer {
    if (!HvigorDaemonServer.instance) {
      HvigorDaemonServer.instance = new HvigorDaemonServer(sessionId);
    }
    return HvigorDaemonServer.instance;
  }

  getHttpServer(): http.Server {
    return this.httpServer;
  }

  getSessionId(): string {
    return this.sessionId;
  }

  onConnection(listener: (socket: Socket) => void) {
    this.server.on(DaemonServerEventName.CONNECTION, listener);
  }

  onError(listener: (err: Error) => void) {
    this.server.on(DaemonServerEventName.ERROR, listener);
  }

  listen(port?: number, hostname?: string, listeningListener?: () => void) {
    this.httpServer.listen(port, hostname, listeningListener);
  }

  onListening(listener: () => void) {
    this.httpServer.on(DaemonServerEventName.LISTENING, listener);
  }

  onListenFailed(listener: (message: string) => void) {
    this.on(DaemonServerEventName.LISTEN_FAILED, listener);
  }

  onCloseConnection(listener: (...args: any[]) => void) {
    this.on(DaemonServerEventName.CLOSE_CONNECTION, listener);
  }

  onCloseServer(listener: (...args: any[]) => void) {
    this.on(DaemonServerEventName.CLOSE_SERVER, listener);
  }
}
